package com.bytz.modules.cms.auditBatch.service.change;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bytz.common.constant.CommonConstant;
import com.bytz.common.exception.BytzBootException;
import com.bytz.modules.cms.auditBatch.model.ResellerLevelChangeExcel;
import com.bytz.modules.cms.auditBatch.service.IChangeService;
import com.bytz.modules.cms.productLine.entity.ProductLineLevel;
import com.bytz.modules.cms.productLine.service.IProductLineLevelService;
import com.bytz.modules.cms.reseller.entity.Reseller;
import com.bytz.modules.cms.reseller.entity.ResellerLevel;
import com.bytz.modules.cms.reseller.entity.ResellerLevelChange;
import com.bytz.modules.cms.reseller.mapper.ResellerLevelChangeMapper;
import com.bytz.modules.cms.reseller.service.IResellerLevelService;
import com.bytz.modules.cms.reseller.service.IResellerService;
import com.bytz.modules.cms.user.constants.AuditBatchConstants;
import com.bytz.modules.cms.user.service.IAuditBatchService;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class BatchResellerChangeServiceImpl extends ServiceImpl<ResellerLevelChangeMapper, ResellerLevelChange> implements IChangeService<ResellerLevelChange> {

    @Autowired
    private IResellerLevelService resellerLevelService;

    @Autowired
    private IAuditBatchService auditBatchService;

    @Autowired
    private IResellerService resellerService;

    @Autowired
    private IProductLineLevelService productLineLevelService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncChange(String batchId) {

        List<ResellerLevelChange> changeList = setResellerLevelId(batchId);

        if (CollectionUtil.isEmpty(changeList)) {
            return;
        }

        Map<String, List<ResellerLevelChange>> idGroup = changeList.stream()
                .collect(Collectors.groupingBy(ResellerLevelChange::getResellerLevelId));

        List<ResellerLevel> updateList = idGroup.keySet().stream().map(id -> {
            ResellerLevel updateEntity = new ResellerLevel();
            updateEntity.setId(id);

            idGroup.get(id).stream().findFirst().ifPresent(resellerLevel -> {

                updateEntity.setId(resellerLevel.getResellerLevelId());
                updateEntity.setResellerId(resellerLevel.getResellerId());
                updateEntity.setProductLineLevelId(resellerLevel.getLevelId());
                updateEntity.setEffectTime(LocalDateTime.now());
            });
            return updateEntity;
        }).collect(Collectors.toList());

        updateSyncData(batchId, updateList);
    }

    /**
     * 获取主表id，并保存到change表中
     * 主表不存在相应数据的，给主表中添加一条
     */
    private List<ResellerLevelChange> setResellerLevelId(String batchId) {

        // 填入主表id
        MPJLambdaWrapper<ResellerLevelChange> wrapper = new MPJLambdaWrapper<>();

        List<ResellerLevelChange> result = baseMapper.selectJoinList(ResellerLevelChange.class, wrapper
                .selectAll(ResellerLevelChange.class)
                .selectAs(ResellerLevel::getId, ResellerLevelChange::getResellerLevelId)
                .leftJoin(ResellerLevel.class, on -> on
                        .eq(ResellerLevelChange::getResellerId, ResellerLevel::getResellerId)
                        .eq(ResellerLevelChange::getProductLineId, ResellerLevel::getProductLineId)
                        .eq(ResellerLevel::getDelFlag, CommonConstant.DEL_FLAG_0)
                )
                .eq(ResellerLevelChange::getAuditBatchId, batchId)
                .eq(ResellerLevelChange::getSyncStatus, AuditBatchConstants.SyncStatus.WAITING_SYNC)
        );

        List<ResellerLevel> insertList = result.stream()
                .filter(change -> change.getResellerLevelId() == null)
                .map(change -> {
                    // 如果主表中没有分类等级都对应的记录，添加一条
                    ResellerLevel insertLevel = new ResellerLevel();
                    insertLevel.setResellerId(change.getResellerId());
                    insertLevel.setProductLineLevelId(change.getLevelId());
                    insertLevel.setProductLineId(change.getProductLineId());
                    insertLevel.setEffectTime(LocalDateTime.now());
                    return insertLevel;
                }).collect(Collectors.toList());

        if (CollectionUtil.isNotEmpty(insertList)) {

            resellerLevelService.saveBatch(insertList);

            Map<String, String> insertMap = insertList.stream()
                    .collect(Collectors.toMap(t -> t.getResellerId() + t.getProductLineId(), ResellerLevel::getId));

            result.forEach(change -> {
                String id = insertMap.get(change.getResellerId() + change.getProductLineId());
                if (id != null) {
                    change.setResellerLevelId(id);
                }
            });
        }

        updateBatchById(result);

        return result;
    }

    /**
     * 更改auditBatch表 将对应id设置为已同步
     * 更改change表 对应batchId设置为已同步
     * 更新对应的主表
     */
    private void updateSyncData(String batchId, List<ResellerLevel> updateList) {

        resellerLevelService.updateBatchById(updateList);

        lambdaUpdate()
                .eq(ResellerLevelChange::getAuditBatchId, batchId)
                .set(ResellerLevelChange::getSyncStatus, AuditBatchConstants.SyncStatus.SYNCED)
                .update();

        auditBatchService.setStatusSynced(batchId);

        // 经销商等级同步后，把reseller表的levels字段更新为顿号隔开的等级名
        updateList.stream().map(ResellerLevel::getResellerId).distinct().forEach(id -> {
            resellerService.resetLevels(id);
        });
    }

    @Override
    public List<ResellerLevelChange> getByBatchId(String batchId) {
        return lambdaQuery()
                .eq(ResellerLevelChange::getAuditBatchId, batchId)
                .list();
    }

    @Override
    public void removeByBatchId(String batchId) {
        lambdaUpdate().eq(ResellerLevelChange::getAuditBatchId, batchId).remove();
    }

    @Override
    public SFunction<ResellerLevelChange, String> getKeyExtractor() {
        return ResellerLevelChange::getResellerLevelId;
    }

    @Override
    public List<ResellerLevelChange> importExcel(List<ResellerLevelChange> models) {
        // 这个表里没有前端回显所用到的所有字段，importExcel方法弃用
        return null;
    }

    public List<ResellerLevelChangeExcel> fillIdByExcel(List<ResellerLevelChangeExcel> models) {

        Map<String, Reseller> resellerNameIdMap = resellerService.getByNames(models.stream().map(ResellerLevelChangeExcel::getResellerName).collect(Collectors.toSet()))
                .stream().collect(Collectors.toMap(Reseller::getResellerName, t -> t));


        Map<String, ProductLineLevel> levelMap = productLineLevelService.getByNames(models.stream().map(ResellerLevelChangeExcel::getLevelName).collect(Collectors.toSet()))
                .stream().collect(Collectors.toMap(ProductLineLevel::getLevelName, t -> t));

        models.forEach(excel -> {
            Reseller reseller = resellerNameIdMap.get(excel.getResellerName());
            if (reseller == null) {
                throw new BytzBootException(String.format("找不到经销商【%s】", excel.getResellerName()));
            }
            excel.setResellerId(reseller.getId());
            excel.setContactPerson(reseller.getContactPerson());

            ProductLineLevel level = levelMap.get(excel.getLevelName());
            if (level == null) {
                throw new BytzBootException(String.format("找不到等级【%s】", excel.getLevelName()));
            }
            excel.setLevelId(level.getId());
            excel.setProductLineId(level.getProductLineId());
            excel.setProductLineName(level.getProductLineName());
            excel.setSort(level.getSort());
        });
        return models;
    }
}
